<!DOCTYPE html>
<html>

<head>
  <title>Using Software Transactional Memory in Quarkus</title>
  <script id="adobe_dtm" src="https://www.redhat.com/dtm.js" type="text/javascript"></script>
  <script src="/assets/javascript/highlight.pack.js" type="text/javascript"></script>
  <META HTTP-EQUIV='Content-Security-Policy' CONTENT="default-src 'none'; script-src 'self' 'unsafe-eval' 'sha256-ANpuoVzuSex6VhqpYgsG25OHWVA1I+F6aGU04LoI+5s=' 'sha256-ipy9P/3rZZW06mTLAR0EnXvxSNcnfSDPLDuh3kzbB1w=' js.bizographics.com https://www.redhat.com assets.adobedtm.com jsonip.com https://ajax.googleapis.com https://www.googletagmanager.com https://www.google-analytics.com https://use.fontawesome.com; style-src 'self' https://fonts.googleapis.com https://use.fontawesome.com; img-src 'self' *; media-src 'self' ; frame-src https://www.googletagmanager.com https://www.youtube.com; frame-ancestors 'none'; base-uri 'none'; object-src 'none'; form-action 'none'; font-src 'self' https://use.fontawesome.com https://fonts.gstatic.com;">
  <META HTTP-EQUIV='X-Frame-Options' CONTENT="DENY">
  <META HTTP-EQUIV='X-XSS-Protection' CONTENT="1; mode=block">
  <META HTTP-EQUIV='X-Content-Type-Options' CONTENT="nosniff">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Quarkus: Supersonic Subatomic Java">
  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:site" content="@QuarkusIO"> 
  <meta name="twitter:creator" content="@QuarkusIO">
  <meta property="og:url" content="https://quarkus.io/guides/software-transactional-memory" />
  <meta property="og:title" content="Using Software Transactional Memory in Quarkus" />
  <meta property="og:description" content="Quarkus: Supersonic Subatomic Java" />
  <meta property="og:image" content="/assets/images/quarkus_card.png" />
  <link rel="canonical" href="https://quarkus.io/guides/software-transactional-memory">
  <link rel="shortcut icon" type="image/png" href="/favicon.ico" >
  <link rel="stylesheet" href="https://quarkus.io/guides/stylesheet/config.css" />
  <link rel="stylesheet" href="/assets/css/main.css" />
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
  <link rel="alternate" type="application/rss+xml"  href="https://quarkus.io/feed.xml" title="Quarkus">
  <script src="https://quarkus.io/assets/javascript/goan.js" type="text/javascript"></script>
  <script src="https://quarkus.io/assets/javascript/hl.js" type="text/javascript"></script>
</head>

<body class="guides">
  <!-- Google Tag Manager (noscript) -->
  <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NJWS5L"
  height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
  <!-- End Google Tag Manager (noscript) -->

  <div class="nav-wrapper">
  <div class="grid-wrapper">
    <div class="width-12-12">
      <input type="checkbox" id="checkbox" />
      <nav id="main-nav" class="main-nav">
  <div class="container">
    <div class="logo-wrapper">
      
        <a href="/"><img src="/assets/images/quarkus_logo_horizontal_rgb_600px_reverse.png" class="project-logo" title="Quarkus"></a>
      
    </div>
    <label class="nav-toggle" for="checkbox">
      <i class="fa fa-bars"></i>
    </label>
    <div id="menu" class="menu">
      <span>
        <a href="/get-started/" class="">Get Started</a>
      </span>
      <span>
        <a href="/guides/" class="active">Guides</a>
      </span>
      <span>
        <a href="/community/" class="">Community</a>
      </span>
      <span>
        <a href="/support/" class="">Support</a>
      </span>
      <span>
        <a href="/blog/" class="">Blog</a>
      </span>
      <span>
        <a href="https://code.quarkus.io" class="button-cta secondary white">Start Coding</a>
      </span>
    </div>
  </div>
      </nav>
    </div>
  </div>
</div>

  <div class="content">
    <div class="guide">
  <div class="width-12-12">
    <h1 class="text-caps">Using Software Transactional Memory in Quarkus</h1>
    <div class="hide-mobile toc"><ul class="sectlevel1">
<li><a href="#why-use-stm-with-quarkus">Why use STM with Quarkus?</a></li>
<li><a href="#building-stm-applications">Building STM applications</a></li>
<li><a href="#setting-it-up">Setting it up</a></li>
<li><a href="#defining-stm-aware-classes">Defining STM-aware classes</a></li>
<li><a href="#creating-stm-objects">Creating STM objects</a></li>
<li><a href="#defining-transaction-boundaries">Defining transaction boundaries</a>
<ul class="sectlevel2">
<li><a href="#declarative-approach">Declarative approach</a></li>
<li><a href="#programmatic-approach">Programmatic approach</a></li>
</ul>
</li>
<li><a href="#distributed-transactions">Distributed transactions</a></li>
</ul></div>
    <div>
      <div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Software Transactional Memory (STM) has been around in research environments since the late
1990&#8217;s and has relatively recently started to appear in products and various programming
languages. We won&#8217;t go into all of the details behind STM but the interested reader could look at <a href="https://groups.csail.mit.edu/tds/papers/Shavit/ShavitTouitou-podc95.pdf">this paper</a>.
However, suffice it to say that STM offers an approach to developing transactional applications in a highly
concurrent environment with some of the same characteristics of ACID transactions, which you&#8217;ve probably already used
through JTA. Importantly though, the Durability property is relaxed (removed) within STM implementations,
or at least made optional. This is not the situation with JTA, where state changes are made durable
to a relational database which supports <a href="https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf">the X/Open XA
standard</a>.</p>
</div>
<div class="paragraph">
<p>Note, the STM implementation provided by Quarkus is based on the <a href="https://narayana.io/docs/project/index.html#d0e16066">Narayana STM</a> implementation. This document isn&#8217;t meant to be a replacement for that project&#8217;s documentation so you may want
to look at that for more detail. However, we will try to focus more on how you can combine some of the key capabilities
into Quarkus when developing Kubernetes native applications and microservices.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="why-use-stm-with-quarkus"><a class="anchor" href="#why-use-stm-with-quarkus"></a>Why use STM with Quarkus?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Now you may still be asking yourself "Why STM instead of JTA?" or "What are the benefits
to STM that I don&#8217;t get from JTA?" Let&#8217;s try to answer those or similar questions, with
a particular focus on why we think they&#8217;re great for Quarkus, microservices and Kubernetes
native applications. So in no specific order &#8230;&#8203;</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The goal of STM is to simplify object reads and writes from multiple threads/protect
state from concurrent updates. The Quarkus STM implementation will safely manage any conflicts between
these threads using whatever isolation model has been chosen to protect that specific state
instance (object in the case of Quarkus). In Quarkus STM, there are two isolation implementations,
pessimistic (the default), which would cause conflicting threads to be blocked until the original
has completed its updates (committed or aborted the transaction); then there&#8217;s the optimistic
approach which allows all of the threads to proceed and checks for conflicts at commit time, where
one or more of the threads may be forced to abort if there have been conflicting updates.</p>
</li>
<li>
<p>STM objects have state but it doesn&#8217;t need to be persistent (durable). In fact the
default behaviour is for objects managed within transactional memory to be volatile, such that
if the service or microservice within which they are being used crashes or is spawned elsewhere, e.g.,
by a scheduler, all state in memory is lost and the objects start from scratch. But surely you get this and more
with JTA (and a suitable transactional datastore) and don&#8217;t need to worry about restarting your application?
Not quite. There&#8217;s a trade-off here: we&#8217;re doing away
with persistent state and the overhead of reading from and then writing (and sync-ing) to the datastore during each
transaction. This makes updates to (volatile) state very fast but you still get the benefits of atomic updates
across multiple STM objects (e.g., objects your team wrote then calling objects you inherited from another team and requiring
them to make all-or-nothing updates), as well as consistency
and isolation in the presence of concurrent threads/users (common in distributed microservices architectures).
Furthermore, not all stateful applications need to be durable - even when JTA transactions are used, it tends to be the
exception and not the rule. And as you&#8217;ll see later, because applications can optionally start and control transactions, it&#8217;s possible to build microservices which can undo state changes and try alternative paths.</p>
</li>
<li>
<p>Another benefit of STM is composability and modularity. You can write concurrent Quarkus objects/services that
can be easily composed with any other services built using STM, without exposing the details of how the objects/services
are implemented. As we discussed earlier, this ability to compose objects you wrote with those other teams may have
written weeks, months or years earlier, and have A, C and I properties can be hugely beneficial. Furthermore, some
STM implementations, including the one Quarkus uses, support nested transactions and these allow changes made within
the context of a nested (sub) transaction to later be rolled back by the parent transaction.</p>
</li>
<li>
<p>Although the default for STM object state is volatile, it is possible to configure the STM implementation
such that an object&#8217;s state is durable. Although it&#8217;s possible to configure Narayana such that different
backend datastores can be used, including relational databases, the default is the local operating system
file system, which means you don&#8217;t need to configure anything else with Quarkus such as a database.</p>
</li>
<li>
<p>Many STM implementations allow "plain old language objects" to be made STM-aware with little or no changes to
the application code. You can build, test and deploy applications without wanting them to be STM-aware and
then later add those capabilities if they become necessary and without much development overhead at all.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="building-stm-applications"><a class="anchor" href="#building-stm-applications"></a>Building STM applications</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There is also a fully worked example in the quickstarts which you may access by cloning the
Git repository: <code>git clone <a href="https://github.com/quarkusio/quarkus-quickstarts.git" class="bare">https://github.com/quarkusio/quarkus-quickstarts.git</a></code>, or by downloading an <a href="https://github.com/quarkusio/quarkus-quickstarts/archive/master.zip">archive</a>.
Look for the <code>software-transactional-memory-quickstart</code> example. This will help to understand how you
can build STM-aware applications with Quarkus. However, before we do so there are a few basic concepts
which we need to cover.</p>
</div>
<div class="paragraph">
<p>Note, as you will see, STM in Quarkus relies on a number of annotations to define behaviours. The lack
of these annotations causes sensible defaults to be assumed but it is important for the developer to
understand what these may be. Please refer to the <a href="https://narayana.io/docs/project/index.html#d0e16066">Narayana STM manual</a>
and the <a href="https://narayana.io//docs/project/index.html#d0e16133">STM annotations guide</a> for more details on
all of the annotations Narayana STM provides.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This technology is considered preview.</p>
</div>
<div class="paragraph">
<p>In <em>preview</em>, backward compatibility and presence in the ecosystem is not guaranteed.
Specific improvements might require to change configuration or APIs and plans to become <em>stable</em> are under way.
Feedback is welcome on our <a href="https://groups.google.com/d/forum/quarkus-dev">mailing list</a> or as issues in our <a href="https://github.com/quarkusio/quarkus/issues">GitHub issue tracker</a>.</p>
</div>
<div class="paragraph">
<p>For a full list of possible extension statuses, check our <a href="https://quarkus.io/faq/#extension-status">FAQ entry</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="setting-it-up"><a class="anchor" href="#setting-it-up"></a>Setting it up</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To use the extension include it as a dependency in your application pom:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="xml" class="language-xml hljs">&lt;dependencies&gt;
    &lt;!-- STM extension --&gt;
    &lt;dependency&gt;
      &lt;groupId&gt;io.quarkus&lt;/groupId&gt;
      &lt;artifactId&gt;quarkus-narayana-stm&lt;/artifactId&gt;
      &lt;version&gt;${quarkus.version}&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="defining-stm-aware-classes"><a class="anchor" href="#defining-stm-aware-classes"></a>Defining STM-aware classes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>In order for the STM subsytem to have knowledge about which classes are to be managed within the context
of transactional memory it is necessary to provide a minimal level of instrumentation. This occurs by
categorising STM-aware and STM-unaware classes through an interface boundary; specifically all STM-aware objects
must be instances of classes which inherit from interfaces that themselves have been annotated to identify them
as STM-aware. Any other objects (and their classes) which do not follow this rule will not be managed by the
STM subsystem and hence any of their state changes will not be rolled back, for example.</p>
</div>
<div class="paragraph">
<p>The specific annotation that STM-aware application interfaces must use is <code>org.jboss.stm.annotations.Transactional</code>.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">@Transactional
public interface FlightService {
    int getNumberOfBookings();
    void makeBooking(String details);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Classes which implement this interface are able to use additional annotations from Narayana to tell the STM
subsystem about things such as whether a method will modify the state of the object, or what state variables
within the class should be managed transactionally, e.g., some instance variables may not need to be rolled back
if a transaction aborts. As mentioned earlier, if those annotations are not present then defaults are chosen to
guarantee safety, such as assuming all methods will modify state.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">public class FlightServiceImpl implements FlightService {
    @ReadLock
    public int getNumberOfBookings() { ... }
    public void makeBooking(String details) {...}

    @NotState
    private int timesCalled;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>For example, by using the <code>@ReadLock</code> annotation on the <code>getNumberOfBookings</code> method, we are able to tell the
STM subsystem that no state modifications will occur in this object when it is used in the transactional
memory. Also, the <code>@NotState</code> annotation tells the system to ignore <code>timesCalled</code> when transactions commit or
abort, so this value only changes due to application code.</p>
</div>
<div class="paragraph">
<p>Please refer to the Narayana guide for details of how to exert finer grained control over the transactional
behaviour of objects that implement interfaces marked with the <code>@Transactional</code> annotation.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="creating-stm-objects"><a class="anchor" href="#creating-stm-objects"></a>Creating STM objects</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The STM subsystem needs to be told about which objects it should be managing. The Quarkus (aka Narayana) STM implementation
does this by providing containers of transactional memory within which these object instances reside. Until an object
is placed within one of these STM containers it cannot be managed within transactions and any state changes will
not possess the A, C, I (or even D) properties.</p>
</div>
<div class="paragraph">
<p>Note, the term "container" was defined within the STM implementation years before Linux containers came along. It may
be confusing to use especially in a Kubernetes native environment such as Quarkus, but hopefully
the reader can do the mental mapping.</p>
</div>
<div class="paragraph">
<p>The default STM container (<code>org.jboss.stm.Container</code>) provides support for volatile objects that can only be shared between
threads in the same microservice/JVM instance. When a STM-aware object is placed into the container it returns a handle
through which that object should then be used in the future. It is important to use this handle as continuing to access
the object through the original reference will not allow the STM subsystem to track access and manage state and
concurrency control.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">    import org.jboss.stm.Container;

    ...

    Container&lt;FlightService&gt; container = new Container&lt;&gt;(); <i class="conum" data-value="1"></i><b>(1)</b>
    FlightServiceImpl instance = new FlightServiceImpl(); <i class="conum" data-value="2"></i><b>(2)</b>
    FlightService flightServiceProxy = container.create(instance); <i class="conum" data-value="3"></i><b>(3)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>You need to tell each Container about the type of objects for which it will be responsible. In this example
it will be instances that implement the FlightService interface.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Then you create an instance that implements <code>FlightService</code>. You should not use it directly at this stage because
access to it is not being managed by the STM subsystem.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>To obtain a managed instance, pass the original object to the STM <code>container</code> which then returns a reference
through which you will be able perform transactional operations. This reference can be used safely from multiple threads.</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="defining-transaction-boundaries"><a class="anchor" href="#defining-transaction-boundaries"></a>Defining transaction boundaries</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Once an object is placed within an STM container the application developer can manage the scope of transactions
within which it is used. There are some annotations which can be applied to the STM-aware class to have the
container automatically create a transaction whenever a specific method is invoked.</p>
</div>
<div class="sect2">
<h3 id="declarative-approach"><a class="anchor" href="#declarative-approach"></a>Declarative approach</h3>
<div class="paragraph">
<p>If the <code>@NestedTopLevel</code> or <code>@Nested</code> annotation is placed on a method signature then the STM container will
start a new transaction when that method is invoked and attempt to commit it when the method returns. If there is
a transaction already associated with the calling thread then each of these annotations behaves slightly differently:
the former annotation will always create a new top-level transaction within which the method will execute, so the enclosing
transaction does not behave as a parent, i.e., the nested top-level transaction will commit or abort independently; the
latter annotation will create a transaction with is properly nested within the calling transaction, i.e., that
transaction acts as the parent of this newly created transaction.</p>
</div>
</div>
<div class="sect2">
<h3 id="programmatic-approach"><a class="anchor" href="#programmatic-approach"></a>Programmatic approach</h3>
<div class="paragraph">
<p>The application can programmatically start a transaction before accessing the methods of STM objects:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code data-lang="java" class="language-java hljs">AtomicAction aa = new AtomicAction(); <i class="conum" data-value="1"></i><b>(1)</b>

aa.begin(); <i class="conum" data-value="2"></i><b>(2)</b>
{
    try {
        flightService.makeBooking("BA123 ...");
        taxiService.makeBooking("East Coast Taxis ..."); <i class="conum" data-value="3"></i><b>(3)</b>
        <i class="conum" data-value="4"></i><b>(4)</b>
        aa.commit();
        <i class="conum" data-value="5"></i><b>(5)</b>
    } catch (Exception e) {
        aa.abort(); <i class="conum" data-value="6"></i><b>(6)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>An object for manually controlling transaction boundaries (AtomicAction and many other useful
classes are included in the extension).
Refer <a href="https://narayana.io//docs/api/com/arjuna/ats/arjuna/AtomicAction.html">to the javadoc</a> for more detail.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Programmatically begin a transaction.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Notice that object updates can be composed which means that updates to multiple objects can be committed together as a single action.
[Note that it is also possible to begin nested transactions so that you can perform speculative work which may then be abandoned
without abandoning other work performed by the outer transaction].</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Since the transaction has not yet been committed the changes made by the flight and taxi services are not visible outside of the transaction.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Since the commit was successful the changes made by the flight and taxi services are now visible to other threads.
Note that other transactions that relied on the old state may or may not now incur conflicts when they commit (the STM library
provides a number of features for managing conflicting behaviour and these are covered in the Narayana STM manual).</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Programmatically decide to abort the transaction which means that the changes made by the flight and taxi services are discarded.</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="distributed-transactions"><a class="anchor" href="#distributed-transactions"></a>Distributed transactions</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Sharing a transaction between multiple services is possible but is currently
an advanced use case only and the Narayana documentation should be consulted
if this behaviour is required. In particular, STM does not yet support the features
described in the <a href="context-propagation">Context Propagation guide</a>.</p>
</div>
</div>
</div>
    </div>
  </div>
</div>

  </div>

  <div class="content project-footer">
  <div class="footer-section">
    <div class="logo-wrapper">
      <a href="/"><img src="/assets/images/quarkus_logo_horizontal_rgb_reverse.svg" class="project-logo" title="Quarkus"></a>
    </div>
  </div>
  <div class="grid-wrapper">
    <p class="grid__item width-3-12">Quarkus is open. All dependencies of this project are available under the <a href='https://www.apache.org/licenses/LICENSE-2.0' target='_blank'>Apache Software License 2.0</a> or compatible license.<br /><br />This website was built with <a href='https://jekyllrb.com/' target='_blank'>Jekyll</a>, is hosted on <a href='https://pages.github.com/' target='_blank'>Github Pages</a> and is completely open source. If you want to make it better, <a href='https://github.com/quarkusio/quarkusio.github.io' target='_blank'>fork the website</a> and show us what you’ve got.</p>

    
      <div class="width-1-12 project-links">
        <span>Navigation</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="/">Home</a></li>
          
            <li><a href="/guides">Guides</a></li>
          
            <li><a href="/community/#contributing">Contribute</a></li>
          
            <li><a href="/faq">FAQ</a></li>
          
            <li><a href="/get-started">Get Started</a></li>
          
        </ul>
      </div>
    
      <div class="width-1-12 project-links">
        <span>Contribute</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="https://twitter.com/quarkusio">Follow us</a></li>
          
            <li><a href="https://github.com/quarkusio">GitHub</a></li>
          
            <li><a href="/security">Security&nbsp;policy</a></li>
          
        </ul>
      </div>
    
      <div class="width-1-12 project-links">
        <span>Get Help</span>
        <ul class="footer-links width-1-12">
          
            <li><a href="https://groups.google.com/forum/#!forum/quarkus-dev">Forums</a></li>
          
            <li><a href="https://quarkusio.zulipchat.com">Chatroom</a></li>
          
        </ul>
      </div>
    

    
      <div class="width-3-12 more-links">
        <span>Quarkus is made of community projects</span>
        <ul class="footer-links">
          
            <li><a href="https://vertx.io/" target="_blank">Eclipse Vert.x</a></li>
          
            <li><a href="https://microprofile.io" target="_blank">Eclipse MicroProfile</a></li>
          
            <li><a href="https://hibernate.org" target="_blank">Hibernate</a></li>
          
            <li><a href="https://netty.io" target="_blank">Netty</a></li>
          
            <li><a href="https://resteasy.github.io" target="_blank">RESTEasy</a></li>
          
            <li><a href="https://camel.apache.org" target="_blank">Apache Camel</a></li>
          
            <li><a href="https://code.quarkus.io/" target="_blank">And many more...</a></li>
          
        </ul>
      </div>
    
  </div>
</div>
  <div class="content redhat-footer">
  <div class="grid-wrapper">
    <span class="licence">
      <i class="fab fa-creative-commons"></i><i class="fab fa-creative-commons-by"></i> <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank">CC by 3.0</a> | <a href="https://www.redhat.com/en/about/privacy-policy">Privacy Policy</a>
    </span>
    <span class="redhat">
      Sponsored by
    </span>
    <span class="redhat-logo">
      <a href="https://www.redhat.com/" target="_blank"><img src="/assets/images/redhat_reversed.svg"></a>
    </span>
  </div>
</div>


  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js" integrity="sha384-8gBf6Y4YYq7Jx97PIqmTwLPin4hxIzQw5aDmUg/DDhul9fFpbbLcLh3nTIIDJKhx" crossorigin="anonymous"></script>
  <script type="text/javascript" src="/assets/javascript/mobile-nav.js"></script>
  <script type="text/javascript" src="/assets/javascript/scroll-down.js"></script>
  <script src="/assets/javascript/satellite.js" type="text/javascript"></script>
  <script src="https://quarkus.io/guides/javascript/config.js" type="text/javascript"></script>
  <script src="/assets/javascript/search-filter.js" type="text/javascript"></script>
  <script src="/assets/javascript/back-to-top.js" type="text/javascript"></script>
</body>

</html>
